<template>
  <div>
    <dg-table class="common-table" ref="table" stripe :border="false" :data="tableData" :pagination="false">
      <template v-for="(column, index) in tableColumns">
        <dg-table-column
          :key="index"
          v-if="column.type === 'selection'"
          v-bind="column"
          :selectable="selectInit"
          :reserve-selection="column.reserveSelection"
        >
        </dg-table-column>

        <dg-table-column
          :key="index"
          v-if="column.type === 'index'"
          v-bind="column"
          :label="column.label"
        ></dg-table-column>

        <dg-table-column
          :key="index"
          v-if="column.type === 'slot'"
          v-bind="column"
          v-slot="scope"
          :label="column.label"
        >
          <slot :name="column.prop" v-bind="scope"></slot>
        </dg-table-column>

        <dg-table-column
          :key="index"
          v-if="column.type === 'expand'"
          type="expand"
          v-slot="scope"
          :label="column.label"
        >
          <slot :name="column.prop" v-bind="scope"></slot>
        </dg-table-column>

        <dg-table-column
          :key="index"
          v-if="!column.type || column.type === 'text'"
          v-bind="column"
          show-overflow-tooltip
          :label="column.label"
        >
          <template v-slot="{ row, formatValue }">
            <span v-if="column.code">{{ formatValue | doFilters(column.doFilters) }}</span>
            <span v-else>{{ row[column.prop] | doFilters(column.doFilters) }}</span>
          </template>
        </dg-table-column>
      </template>

      <!--无数据-->
      <slot name="empty" slot="empty">
        <no-record :height="noDataHeight"></no-record>
      </slot>
    </dg-table>
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="paginationPropsData.currentPage"
      :page-sizes="[5, 10, 15, 20]"
      :page-size="paginationPropsData.pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="paginationTotal"
    >
    </el-pagination>
  </div>
</template>

<script>
import { debounce } from '@/utils/data-utils';
import * as $filters from '@/filters';

export default {
  name: 'common-table',
  props: {
    columns: {
      type: Array,
      default() {
        return [];
      }
    },
    requestFcun: {
      type: Function,
      default() {
        return () => {};
      }
    },
    noDataHeight: {
      type: String,
      default: '200px'
    },
    // 文本溢出时的展示方式
    overflow: {
      type: String,
      default: 'false'
    },
    rowKey: {
      type: [String, Function],
      default: 'id'
    },
    paginationProps: {
      type: Object,
      default: () => {
        return {};
      }
    },
    condition: {
      type: Object,
      default: () => {
        return {
          page: 0,
          size: 0,
          sort: [],
          searchCondition: {}
        };
      }
    },
    url: {
      type: String,
      default: ''
    },
    immediate: {
      type: Boolean,
      default: false
    }
  },
  // 组件内部参数
  data() {
    const defaultPageConfig = {
      currentPage: 0,
      pageSizes: [5, 10, 20],
      pageSize: 5,
      layout: 'total, sizes, prev, pager, next, jumper'
    };
    const propPageConfig = Object.keys(this.paginationProps).length
      ? Object.assign({}, defaultPageConfig, this.paginationProps)
      : defaultPageConfig;
    return {
      // 分页设置
      paginationPropsData: propPageConfig,
      tableColumns: [],
      tableData: [],
      paginationTotal: 0
    };
  },
  watch: {
    columns: {
      handler: function(newVal) {
        if (Object.prototype.toString.call(newVal) === '[object Array]') {
          this.$nextTick(() => {
            const style = window.getComputedStyle(this.$el);
            const tableWidth = parseInt(style.width);
            let lastWidth =
              tableWidth -
              newVal.reduce((total, item) => {
                let width = 0;
                if ('string' === typeof item.width && !item.width.endsWith('%')) {
                  width = parseInt(item.width);
                  if (item.width.endsWith('em')) {
                    width = (width * parseInt(style.fontSize)) << 0;
                  }
                  item.width = width;
                }
                if (typeof item.width === 'number') {
                  width = item.width;
                }
                return total + width;
              }, 0);
            if (lastWidth <= 0) {
              lastWidth = tableWidth;
            }
            this.tableColumns = newVal.map(item => {
              item.minWidth = item.minWidth ? item.minWidth : '6em';
              if ('string' === typeof item.width && item.width.endsWith('%')) {
                const width = parseInt(item.width);
                item.width = ((lastWidth * width) / 100) << 0;
              }
              if (item['min-width']) {
                item.minWidth = item.minWidth || item['min-width'];
                delete item['min-width'];
              }
              if (item['max-width']) {
                item.maxWidth = item.maxWidth || item['max-width'];
                delete item['max-width'];
              }
              if ('string' === typeof item.minWidth) {
                const width = parseInt(item.minWidth);
                if (item.minWidth.endsWith('%')) {
                  item.minWidth = ((lastWidth * width) / 100) << 0;
                }
                if (item.minWidth.endsWith('em')) {
                  item.minWidth = (width * parseInt(style.fontSize)) << 0;
                }
                if (item.width < item.minWidth) {
                  item.width = item.minWidth;
                }
              }
              if ('string' === typeof item.maxWidth) {
                const width = parseInt(item.maxWidth);
                if (item.maxWidth.endsWith('%')) {
                  item.maxWidth = ((lastWidth * width) / 100) << 0;
                }
                if (item.maxWidth.endsWith('em')) {
                  item.maxWidth = (width * parseInt(style.fontSize)) << 0;
                }
                if (item.width > item.maxWidth) {
                  item.width = item.maxWidth;
                }
              }
              return item;
            });
          });
        }
      },
      immediate: true
    }
  },
  components: {},
  methods: {
    init() {
      if (this.immediate) {
        this.search();
      }
    },
    handleSizeChange(val) {
      this.paginationPropsData.pageSize = val;
      this.$emit('handleSizeChange', val);
    },
    handleCurrentChange(index) {
      this.paginationPropsData.currentPage = index;
      this.$emit('handleCurrentChange', index);
    },
    /**
     * 设置表格复选框可点击状态
     * @param {Object} row 单条数据
     * @param {Number} index 数据索引
     */
    selectInit(row) {
      if (this.columns.length && this.columns[0].selectInit) {
        const obj = this.columns[0].selectInit;
        for (let val of obj) {
          if (row[val.disabledKey] !== val.disabledVal) {
            return true;
          }
        }
        return false;
      }
      return true;
    },
    /**
     * 搜索数据, 页面会回到第一页
     * @param {Object} condition 搜索条件
     * @return {undefined} 无
     */
    search(func, condition = this.condition, pageConfig) {
      // 切换tab时，回到第一页且保持页码属性一致
      const { currentPage, pageSize } = pageConfig;
      this.paginationPropsData.currentPage = currentPage || this.paginationPropsData.currentPage;
      this.paginationPropsData.pageSize = pageSize || this.paginationPropsData.pageSize;
      debounce(() => {
        const reqFunc = func || this.requestFcun;
        reqFunc(condition).then(res => {
          if (res.data && res.data.content) {
            this.paginationTotal = res.data.totalElements;
            this.tableData = res.data.content;
          }
        });
      })();
    },
    /**
     * 重新加载数据
     * @param {Object} params 请求参数
     * @return {undefined} 无
     */
    reload(params) {
      this.search(params);
    },
    /**
     * 执行表格的内置方法
     * @param {Function} fn 方法名
     * @param {Object} params 参数
     * @return {undefined} 无
     */
    hanleTableFn(fn, params) {
      let instance = this.$refs.table;
      const doFn = instance && instance[fn];
      if (doFn) {
        doFn(params);
      }
    }
  },
  filters: {
    doFilters(str, filters) {
      const emptyFlag = str === null || str === undefined || (typeof str === 'string' && str.trim() === '');
      if (!emptyFlag && filters) {
        filters.split(',').forEach(filter => {
          str = $filters[filter](str);
        });
      }
      str = emptyFlag ? '-' : str;
      return str;
    }
  },
  created() {
    this.init();
  },
  mounted() {}
};
</script>

<style lang="scss" scoped>
/deep/.el-pagination {
  display: inline-block;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  width: 100%;
  text-align: right;
  padding: 1rem 0 0;
}
.common-table {
  padding: 1rem 0;
}
</style>
